﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum EventType
{
    On_UPDATE_GOLD,
    On_OPEN_PANEL,
    
    Game_OPT_END,
    Game_Move_END,
}

public class EventCenter:Singleton<EventCenter>
{
    public static Dictionary<EventType, Delegate> m_EventTable = new Dictionary<EventType, Delegate>();

    //事件监听的处理函数（从事件监听函数中独立封装出来，提高代码复用性），
    //传入两个参数：事件类型和委托，先判断字典中有无这个事件类型的key值（后面在事件发生脚本中会传入发生的事件类型与要执行的函数）。
    //如果没有就将该事件类型与null存入字典，如果有就获取字典中该事件类型对应的委托，假如当前委托不为空也不等于传入的委托（相当函数），
    //就抛出如下代码中的提示。
    public static void OnListenerAdding(EventType eventType, Delegate callBack)
    {
        if (!m_EventTable.ContainsKey(eventType))
        {
            m_EventTable.Add(eventType, null);
        }
        Delegate d = m_EventTable[eventType];
        if (d != null && d.GetType() != callBack.GetType())
        {
            throw new Exception(string.Format("尝试为事件{0}添加不同类型的委托，当前事件对应类型的委托为{1}，要添加的委托为{2}", eventType, d.GetType(), callBack.GetType()));
        }
    }

    ///// 事件移除监听的处理函数（从事件移除监听函数中独立封装出来，提高代码复用性），
    /// 传入两个参数：事件类型和委托，先判断字典中有无这个事件类型的key值。
    /// 有三种情况：
    /// 1、字典中存在该事件类型但对应委托为空，
    /// 2、事件类型对应委托不等于传入委托，
    /// 3、事件类型不存在于字典中，不同的情况抛出如下代码中的不同提示。
    public static void OnListenerRemoving(EventType eventType, Delegate callBack)
    {
        if (m_EventTable.ContainsKey(eventType))
        {
            Delegate d = m_EventTable[eventType];
            if (d == null)
            {
                throw new Exception(string.Format("移除事件错误：事件{0}没有对应的委托", eventType));
            }
            else if (d.GetType() != callBack.GetType())
            {
                throw new Exception(string.Format("移除事件错误：尝试为事件{0}移除不同类型的委托，当前事件委托为{1}，要移除的委托类型为{2}", eventType, d.GetType(), callBack.GetType()));
            }
        }
        else
        {
            throw new Exception(string.Format("移除事件错误：没有事件码{0}", eventType));
        }
    }

    //监听移除后的处理函数OnListenerRemoved，该函数实现移除字典中的事件数据，因为事件监听已移除，不能继续存储。
    public static void OnListenerRemoved(EventType eventType)
    {
        if (m_EventTable[eventType] == null)
        {
            m_EventTable.Remove(eventType);
        }
    }

    //无参函数添加监听，执行添加监听处理函数，将delegate类型的m_EventTable[eventType]强转为CallBack类型并添加传入的事件callback，再赋予m_EventTable[eventType]。
    public static void AddListener(EventType eventType,Action callBack)
    {
        OnListenerAdding(eventType, callBack);
        m_EventTable[eventType] = (Action)m_EventTable[eventType] + callBack;
    }

    //有参函数添加监听。
    public static void AddListener<T>(EventType eventType,Action<T> callBack)
    {
        OnListenerAdding(eventType, callBack);
        m_EventTable[eventType] = (Action<T>)m_EventTable[eventType] + callBack;
    }

    //无参函数移除监听，调用监听移除处理函数OnListenerRemoving和移除监听后的处理函数，中间减去传入的事件。
    public static void RemoveListener(EventType eventType,Action callBack)
    {
        OnListenerRemoving(eventType, callBack);
        m_EventTable[eventType] = (Action)m_EventTable[eventType] - callBack;
        OnListenerRemoved(eventType);
    }

    //有参函数移除监听。
    public static void RemoveListener<T>(EventType eventType,Action<T> callBack)
    {
        OnListenerRemoving(eventType, callBack);
        m_EventTable[eventType] = (Action<T>)m_EventTable[eventType] - callBack;
        OnListenerRemoved(eventType);
    }
    
    //无参广播函数，该函数会判断字典中有无传入的事件类型并返回对应的委托，用CallBack委托接收返回的委托并调用。
    public static void BroadCast(EventType eventType)
    {
        Delegate d;
        if(m_EventTable.TryGetValue(eventType,out d))
        {
            Action callBack = d as Action;
            if (callBack != null)
            {
                callBack();
            }
            else
            {
                throw new Exception(string.Format("广播事件错误：事件{0}的委托具有不同类型",eventType));
            }
        }
    }

    //有参广播函数。
    public static void BroadCast<T>(EventType eventType,T arg)
    {
        Delegate d;
        if (m_EventTable.TryGetValue(eventType, out d))
        {
            Action<T> callBack = d as Action<T>;
            if (callBack != null)
            {
                callBack(arg);
            }
            else
            {
                throw new Exception(string.Format("广播事件错误：事件{0}的委托具有不同类型", eventType));
            }
        }
    }

}